/*
 * Copyright (c) $today.year-Now http://www.zxpnet.com All rights reserved.
 */

package com.zxp.common.core.validatecode.impl;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.wf.captcha.base.Captcha;
import com.wf.captcha.utils.CaptchaUtil;
import com.zxp.common.core.constant.module.SecurityConstants;
import com.zxp.common.core.security.properties.SecurityProperties;
import com.zxp.common.core.validatecode.ValidateCodeProperties;
import com.zxp.common.core.validatecode.ValidateCodeServiceI;
import com.zxp.common.core.validatecode.bean.ValidateCode;
import com.zxp.common.core.validatecode.bean.image.ImageValidateCode;
import com.zxp.common.core.validatecode.captcha.CaptchaHelper;
import com.zxp.common.core.validatecode.exception.ValidateCodeException;
import com.zxp.common.utils.WebUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.ServletRequestUtils;
import org.springframework.web.context.request.ServletWebRequest;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.concurrent.TimeUnit;

/**
 * @author: shollin
 * @date: 2021/7/6/006 11:04
 */
@Slf4j
@RequiredArgsConstructor
public class ImageValidateCodeService implements ValidateCodeServiceI {

    private final SecurityProperties securityProperties;
    private final RedisTemplate<String,Object> redisTemplate;

    public Captcha generate(ServletWebRequest request) {

        Integer width = ServletRequestUtils.getIntParameter(request.getRequest(),"width",securityProperties.getCode().getImage().getWidth());
        Integer height = ServletRequestUtils.getIntParameter(request.getRequest(),"height",securityProperties.getCode().getImage().getHeight());
        Integer len = ServletRequestUtils.getIntParameter(request.getRequest(),"len",securityProperties.getCode().getImage().getLength());
        Integer type = ServletRequestUtils.getIntParameter(request.getRequest(),"type",1);

        Captcha captcha = CaptchaHelper.getEasyCaptcha(width, height, len, type);
        captcha.setCharType(Captcha.TYPE_ONLY_NUMBER);
        return captcha;
    }

    public void save(ServletWebRequest request, ValidateCode code) {
        String uuid = request.getParameter("uuid");
        if(StrUtil.isBlank(uuid)){
            uuid = WebUtil.getCookieVal(SecurityConstants.CAPTCHA_COOKIENAME_UUID);
        }
        // 参数中没有传uuid,cookie中也没有的话，则抛异常
        if(StrUtil.isBlank(uuid)){
            throw new ValidateCodeException("请传uuid参数");
        }
// SecurityConstants.CAPTCHA_EXPIRED_TIME
        redisTemplate.opsForValue().set(uuid,code.getCode(), code.getExpireSends() , TimeUnit.SECONDS);
    }

    @Override
    public void sendCode(ServletWebRequest request) throws Exception {

        // 生成验证码
        Captcha captcha =   generate(request);
        String verCode = captcha.text(); // 生成的验证码
        log.debug("图片验证码："+verCode);

        // 保存验证码
        String uuid = StrUtil.blankToDefault(request.getParameter("uuid"),WebUtil.getCookieVal(SecurityConstants.CAPTCHA_COOKIENAME_UUID));
        if(StrUtil.isBlank(uuid)){
            throw new ValidateCodeException("参数或者cookie中没有uuid,请检查");
        }
        redisTemplate.opsForValue().set(uuid,verCode, SecurityConstants.CAPTCHA_EXPIRED_TIME , TimeUnit.SECONDS);

        // 发送验证码
        CaptchaUtil.out(captcha, request.getRequest(), request.getResponse());
    }

    @Override
    public void checkCode(ServletWebRequest request) throws ValidateCodeException {

        String code = request.getParameter(SecurityConstants.PARAM_IMAGE_CODE);
        // 校验验证码
        String uuid = StrUtil.blankToDefault(request.getParameter("uuid"),
                WebUtil.getCookieVal(SecurityConstants.CAPTCHA_COOKIENAME_UUID));

        if (StrUtil.isBlank(uuid)) {
            throw new ValidateCodeException("没有uuid");
        }
        Object redisCode = redisTemplate.opsForValue().get(uuid);
        if(ObjectUtil.isEmpty(redisCode)){
            throw new ValidateCodeException("图片验证码已过期");
        }
        if(StrUtil.isBlank(code)){
            throw new ValidateCodeException("请输入图片验证码");
        }
        if(!code.equalsIgnoreCase(redisCode.toString())){
            throw new ValidateCodeException("图片验证码不准确");
        }
    }
}
